
#include <string.h>
#include "sys_service/debug_print_task.h"
#include "bsp_async_comm.h"
#include "bsp_async_comm_config.h"

#ifndef FRAME_PAYLOAD_LEN_MAX
#define FRAME_PAYLOAD_LEN_MAX   16
#endif
#ifndef REC_BUFF_LEN_MAX
#define REC_BUFF_LEN_MAX        32
#endif
#if (REC_BUFF_LEN_MAX < FRAME_PAYLOAD_LEN_MAX)
#error  "REC_BUFF_LEN_MAX mast more then FRAME_PAYLOAD_LEN_MAX"
#endif


#define FRAME_HEAD				0XAA
#define FRAME_escape_character	0XFF

static uint8_t rec_buff[REC_BUFF_LEN_MAX] = {0};
static uint8_t rec_buff_len = 0;
static uint8_t unpackaged_rec_data_buff[FRAME_PAYLOAD_LEN_MAX] = {0};
static uint8_t unpackaged_rec_data_buff_len = 0;
static void (*bsp_async_comm_receive_ok_callback)(uint8_t* unpackaged_rec_data, uint8_t unpackaged_rec_data_len) = 0;

void bsp_async_comm_init(void (*bsp_async_comm_receive_ok_callback_handler)(uint8_t* unpackaged_rec_data, uint8_t unpackaged_rec_data_len))
{
    memset(rec_buff, 0, REC_BUFF_LEN_MAX);
    rec_buff_len = 0;
    memset(unpackaged_rec_data_buff, 0, FRAME_PAYLOAD_LEN_MAX);
    unpackaged_rec_data_buff_len = 0;

    bsp_async_comm_receive_ok_callback = bsp_async_comm_receive_ok_callback_handler;
}

/**********************************************************************************/
//send_frame_data  ----->   send_data
static void framing(uint8_t* frame, uint8_t* frame_payload, uint8_t frame_payload_len)
{
    uint8_t i;
    uint8_t offset;
    frame[0] = FRAME_HEAD;

    offset = 0;
    for(i = 0; i < frame_payload_len; i++){
        frame[i+offset+2] = frame_payload[i];
        if(frame_payload[i] == FRAME_HEAD){
            offset++;
            frame[i+offset+2] = FRAME_HEAD;
        }
    }

    frame[1] = frame_payload_len+offset;
}

uint8_t bsp_async_comm_pack_send_data(uint8_t* packaged_send_data, uint8_t* packaged_send_data_len, uint8_t* original_send_data, uint8_t original_send_data_len)
{
    if(original_send_data_len > FRAME_PAYLOAD_LEN_MAX){
        return 0;
    }

    framing(packaged_send_data, original_send_data, original_send_data_len);
    *packaged_send_data_len = packaged_send_data[1]+2;
    return 1;
}

/**********************************************************************************/
//rec_origin_data  ----->   rec_frame_data
static uint8_t refresh_rec_buff(uint8_t* original_data, uint8_t original_data_len)
{
    if((rec_buff_len+original_data_len) > REC_BUFF_LEN_MAX){
        rec_buff_len = 0;
        sys_debug_print_task_bsp_print_str("hal rec data to long, clr rec buff\r\n");
    }
	if((rec_buff_len+original_data_len) == 0){
        sys_debug_print_task_bsp_print_str("no rec data\r\n");
		return 0;
	}

	memcpy(&(rec_buff[rec_buff_len]), original_data, original_data_len);
    rec_buff_len += original_data_len;

    return 1;
}

static uint8_t frame_find_head(uint8_t* index, uint8_t* rec_buff, uint8_t rec_buff_len)
{
	uint8_t i;
	uint8_t temp_1, temp_2;

    if(rec_buff_len <= 1){
        return 0;
    }

    for(i = 0; i < rec_buff_len-1; i++){
        temp_1 = rec_buff[i];
        temp_2 = rec_buff[i+1];
        if((temp_1 == FRAME_HEAD)&&(temp_2 != FRAME_HEAD)){
            if(rec_buff[i+1] != 0){
                *index = i+2;
                return 1;
            }
        }
    }

    return 0;
}

static uint8_t frame_copy(uint8_t* frame_buff_out, uint8_t* frame_buff_out_len, uint8_t* rec_buff, uint8_t index)
{
    uint8_t offset = 0;
    uint8_t i;
	uint8_t temp_1, temp_2;
	uint8_t frame_payload_len = rec_buff[index-1];
	if(frame_payload_len == FRAME_escape_character){
		frame_payload_len = FRAME_HEAD;
	}

    for(i = 0; (i+offset) < frame_payload_len; i++){
        temp_1 = rec_buff[index+i+offset];
        if(temp_1 == FRAME_HEAD){
            temp_2 = rec_buff[index+i+1+offset];
            if(temp_2 == FRAME_HEAD){
                offset++;
            }
            else{
                sys_debug_print_task_bsp_print_str("frame_copy error\r\n");
                return 0;
            }
        }
        frame_buff_out[i] = temp_1;
    }
	*frame_buff_out_len = i;
    return 1;
}

void bsp_async_comm_rec_data_handler(uint8_t* original_data, uint8_t original_data_len)
{
    uint8_t frame_payload_len;
    uint8_t frame_payload_index;

    if(refresh_rec_buff(original_data, original_data_len) == 0){
        return;
    }

    while(1){
        if(frame_find_head(&frame_payload_index, rec_buff, rec_buff_len) == 1){
            frame_payload_len = rec_buff[frame_payload_index-1];
			if(frame_payload_len == FRAME_escape_character){
				frame_payload_len = FRAME_HEAD;
			}

            if((frame_payload_len+frame_payload_index) <= rec_buff_len){    //the rec frame is complete
                if(frame_copy(unpackaged_rec_data_buff, &unpackaged_rec_data_buff_len, rec_buff, frame_payload_index)){
                    if(bsp_async_comm_receive_ok_callback){
                        bsp_async_comm_receive_ok_callback(unpackaged_rec_data_buff, unpackaged_rec_data_buff_len);
                    }
                }

                if((frame_payload_len+frame_payload_index) == rec_buff_len){
                    sys_debug_print_task_bsp_print_str("finish\r\n");
					rec_buff_len = 0;
                    break;
                }
                else{
					sys_debug_print_task_bsp_print_str("redo\r\n");
                    rec_buff_len = rec_buff_len - (frame_payload_len+frame_payload_index);
                    memcpy(&(rec_buff[0]), &(rec_buff[frame_payload_len+frame_payload_index]), rec_buff_len);
                }
            }
            else{
                sys_debug_print_task_bsp_print_str("the rec frame is NOT complete\r\n");
                break;
            }
        }
        else{
            sys_debug_print_task_bsp_print_str("can't find head\r\n");
        	break;
        }
    }
}
